package hi.system;

import hi.BooleanListener;
import hi.RectangleListener;
import hi.TrackDataListener;

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.util.ArrayList;
import java.util.List;

public class MouseManager implements RectangleListener, BooleanListener, TrackDataListener {

//	public enum Mode {
//		FULLSCREEN, STANDARD
//	}

	Robot mouseRobot;
	Rectangle mouseRect;
	Dimension inputSpan = new Dimension(640, 480);

	int activityCounter = 0;
	int activityThreshold = 2;
	boolean mouseActive = false;

	List<BooleanListener> listeners = new ArrayList<BooleanListener>();
	private boolean controlMouse = true;
	private boolean deactivationIncomplete = false;

	public MouseManager(Rectangle mouseRect) throws AWTException {
		mouseRobot = new Robot();
		this.mouseRect = mouseRect;
	}

	public MouseManager() throws AWTException {
		mouseRobot = new Robot();
		Toolkit toolkit = Toolkit.getDefaultToolkit();  
		Dimension screenSize = toolkit.getScreenSize();
		mouseRect = new Rectangle(0, 0, screenSize.width, screenSize.height);
	}

	@Override
	public void setState(boolean active, int x, int y) {
		if (controlMouse) {
			//placing cursor
			int scaledX = x * mouseRect.width / inputSpan.width + mouseRect.x;
			int scaledY = y * mouseRect.height / inputSpan.height + mouseRect.y;
			//System.out.println("x="+scaledX+" y="+scaledY);
			mouseRobot.mouseMove(scaledX, scaledY);

			//updating mouse state
			boolean prevState = mouseActive;

			if (active) {
				activityCounter++;
			} else {
				activityCounter--;
			}

			if (activityCounter <= 0) {
				mouseActive = false;
				activityCounter = 0;
			} else if (activityThreshold <= activityCounter) {
				mouseActive = true;
				activityCounter = activityThreshold;
			}

			if (mouseActive != prevState) {
				if (mouseActive) {
					mouseRobot.mousePress(InputEvent.BUTTON1_MASK);
				} else {
					mouseRobot.mouseRelease(InputEvent.BUTTON1_MASK);
				}
				//alert listeners -- just the Status Panel at time of writing
				alertListeners(mouseActive);
			}
			
			deactivationIncomplete = true;
		} else if (deactivationIncomplete) { //make sure the mouse is not "left on"
			mouseActive = false;
			//alert listeners -- just the Status Panel at time of writing
			alertListeners(mouseActive);
			activityCounter = 0;
			mouseRobot.mouseRelease(InputEvent.BUTTON1_MASK);
			deactivationIncomplete = false;
		}
	}

	public void addMouseActiveListener(BooleanListener listener) {
		listeners.add(listener);
	}

	public void removeMouseActiveListener(BooleanListener listener) {
		listeners.remove(listener);
	}

	//WARNING: This is very light-weight and basic. If it multiple listeners are actually used,
	//a proper event production scheme should be employed.
	private void alertListeners(boolean active) {
		for(BooleanListener listener : listeners) {
			listener.setActive(active);
		}
	}

	@Override
	public void setRectangle(Rectangle rect) {
		mouseRect = rect;
	}

	//Note: this controls whether the mouse manager is active, not whether the mouse is active
	@Override
	public void setActive(boolean active) {
		controlMouse  = active;
	}

	@Override
	public void setState(boolean primaryActive, int primaryX, int primaryY,
			boolean secondaryActive, int secondaryX, int secondaryY) {
		setState(primaryActive, primaryX, primaryY); //ignores the second input
	}
}
